﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using GeneratorLib.DB;
using GeneratorLib.DB.Schemas;
using UIShell.OSGi;
using Pasys.PresentationCore;
using UIShell.OSGi.Core.Service;
using Pasys.PresentationCore.WinForms;

namespace DBExplorer
{
    public partial class FrmExplorer : Form
    {
        public ConnectionInfos Connections { get; set; }

        private ICommandBusService commandBus;

        public void Invoke(Pasys.PresentationCore.Action action)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new MethodInvoker(action));
            }
            else
            {
                action();
            }
        }


        public FrmExplorer()
        {
            InitializeComponent();
            commandBus = BundleRuntime.Instance.GetFirstOrDefaultService<ICommandBusService>();

            var _extensionManager = BundleRuntime.Instance.GetFirstOrDefaultService<IExtensionManager>();
            var _extensionHooker = new ExtensionHooker(_extensionManager);

            var extensionChangeHandler = new ExtensionChangeHandler(new ToolStripStuffer(this.toolStrip1),null,null);
            _extensionHooker.HookExtension(ExtensionPointNames.ToolStrip, extensionChangeHandler);

            extensionChangeHandler = new ExtensionChangeHandler(new ContextMenuStuffer (this.contextMenuStrip1), null, null);
            _extensionHooker.HookExtension(ExtensionPointNames.Explorer_ContextMenu, extensionChangeHandler);


            commandBus.SubscribeCommandEvent(CommandNames.ConnectionCreated, ConnectionCreated_Handler);
            commandBus.SubscribeCommandEvent(CommandNames.ConnectionChanged, ConnectionChanged_Handler);
            commandBus.SubscribeCommandEvent(CommandNames.ConnectionRemoved, ConnectionRemoved_Handler);
            commandBus.SubscribeCommandEvent(CommandNames.ConnecteConnection, ConnecteConnection_Handler);

            this.Disposed += (s, e) => {
            };
        }

        public override int GetHashCode()
        {
            return string.Format("{0}", this.Connections).GetHashCode();
        }

        public override bool Equals(object obj)
        {
            FrmExplorer obj2 = obj as FrmExplorer;
            if (obj2 == null)
            {
                return false;
            }

            return obj2.Connections == this.Connections;
        }

        private void RemoveToolStrip(ToolStrip control)
        {
            Invoke(() =>
            {
                if (control.Parent != null)
                {
                    control.Parent.Controls.Remove(control);
                }
            });
        }


        public void AddToolStrip(ToolStrip control)
        {
            //The first row is reserved for main menu.
            Invoke(() => {
                control.LayoutStyle = ToolStripLayoutStyle.Flow;
                this.toolStripContainer1.TopToolStripPanel.Join(control, 1); 
            });
        }


        private void FrmExplorer_Load(object sender, EventArgs e)
        {
            loadConnectionInfos();
        }

        private void loadConnectionInfos()
        {
            trvConnections.Nodes.Clear();
            foreach (var info in Connections.Connections)
            {
                AddConnectionInfo(info);
            }
        }

        private void AddConnectionInfo(IConnection info)
        {
            TreeNode node = trvConnections.Nodes.Add(info.Name);
            node.ImageIndex = 0;
            node.SelectedImageIndex = 0;
            node.Tag = info;
            trvConnections.SelectedNode = node;
            //tmConnectDB_Click(node, EventArgs.Empty);
        }

        void ConnectionCreated_Handler(object sender, object e)
        {
            var c = BundleRuntime.Instance.GetFirstOrDefaultService<IConnection>();
            if (c != null)
            {
                AddConnectionInfo(c);
            }
        }

        void ConnectionChanged_Handler(object sender, object e)
        {
             var c = BundleRuntime.Instance.GetFirstOrDefaultService<IConnection>();
             var node = trvConnections.SelectedNode;
             if (c != null && node != null)
             {
                 node.Text = c.Name;
                 node.Tag = c;
             }
        }

        void ConnectionRemoved_Handler(object sender, object e)
        {
            trvConnections.SelectedNode.Remove();
        }

        void ConnecteConnection_Handler(object sender, object e)
        {
            ConnectDB();
        }

        private void trvConnections_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (!SelectNode(e.Node))
            {
                return;
            }
        }

        private void trvConnections_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            TreeViewHitTestInfo testInfo = trvConnections.HitTest(e.X, e.Y);
            if (testInfo.Node == null) return ;
            trvConnections.SelectedNode = testInfo.Node;

            IConnection conInfo = testInfo.Node.Tag as IConnection;
            if (conInfo != null && testInfo.Node.Nodes.Count == 0)
            {
                ConnectDB();
                return;
            }

            TableInfo table = testInfo.Node.Tag as TableInfo;
            if (table != null)
            {
                commandBus.PublicCommand( CommandNames.DBExplorer_Generator_TableInfo);
                return;
            }
        }
        
        private void trvConnections_MouseDown(object sender, MouseEventArgs e)
        {
            TreeViewHitTestInfo testInfo = trvConnections.HitTest(e.X, e.Y);
            if (testInfo.Node != null)
            {
                trvConnections.SelectedNode = testInfo.Node;
                SelectNode(testInfo.Node);
            }

            if (e.Button != System.Windows.Forms.MouseButtons.Right) return;
            contextMenuStrip1.Show(trvConnections, e.Location);

        }


        private void ConnectDB()
        {
            TreeNode node = trvConnections.SelectedNode;
            if (node == null) return;
            if (node.Nodes.Count > 0) return;
            IConnection conInfo = node.Tag as IConnection;
            if (conInfo != null)
            {
                List<TableInfo> tables = conInfo.Tables;
                foreach (var table in tables)
                {
                    TreeNode n = node.Nodes.Add(table.TableName);
                    n.Tag = table;
                    n.ImageIndex = 1;
                    n.SelectedImageIndex = 1;

                }
                node.ExpandAll();
            }
        }

        private bool SelectNode(TreeNode Node)
        {
            IConnection conInfo = Node.Tag as IConnection;
            if (conInfo != null)
            {
                if (ConnectionChanged != null)
                {
                    ConnectionChanged(this, new ConnectionChangedEventArg(conInfo, null));
                }
                return true;
            }

            TableInfo table = Node.Tag as TableInfo;
            if (table != null)
            {
                conInfo = Node.Parent.Tag as IConnection;
                if (ConnectionChanged != null)
                {
                    ConnectionChanged(this, new ConnectionChangedEventArg(conInfo, table));
                }
                return true;
            }

            return false; // testInfo.Node;
        }

        public event EventHandler<ConnectionChangedEventArg> ConnectionChanged;


    }


    public class ConnectionChangedEventArg : EventArgs
    {
        public IConnection ConectionInfo { get; private set; }
        public TableInfo TableInfo { get; private set; }

        public ConnectionChangedEventArg(IConnection conInfo, TableInfo table)
        {
            this.ConectionInfo = conInfo;
            this.TableInfo = table;
        }

    }

}
